using System;
using System.Collections;
using System.Collections.Generic;
using XenoGears.Assertions;
using XenoGears.Reflection;
using XenoGears.Reflection.Generics;
using XenoGears.Reflection.Simple;

namespace Jink.Core.Json.Converters.Shapes.Core
{
    public class JsonMap : IJsonMap
    {
        private Func<Type> _tkey = () => { throw AssertionHelper.Fail(); };
        private Func<Type> _tvalue = () => { throw AssertionHelper.Fail(); };
        private Func<IEnumerable<DictionaryEntry>> _elements = () => { throw AssertionHelper.Fail(); };
        private Action<Object, Object> _add = (key, value) => { throw AssertionHelper.Fail(); };

        private JsonMap(){}

        public static JsonMap ReadOnly(Func<Type> tkey, Func<Type> tvalue, Func<IEnumerable<DictionaryEntry>> elements)
        {
            return new JsonMap{_tkey = tkey, _tvalue = tvalue, _elements = elements};
        }

        public static JsonMap ReadWrite(Func<Type> tkey, Func<Type> tvalue, Func<IEnumerable<DictionaryEntry>> elements, Action<Object, Object> add)
        {
            return new JsonMap{_tkey = tkey, _tvalue = tvalue, _elements = elements, _add = add};
        }

        public Type TKey
        {
            get { return _tkey(); }
        }

        public Type TValue
        {
            get { return _tvalue(); }
        }

        public IEnumerable<DictionaryEntry> Elements
        {
            get { return _elements(); }
        }

        public void Add(Object key, Object value)
        {
            _add(key, value);
        }

        IEnumerable IJsonSeq.Elements
        {
            get { return Elements; }
        }

        Type IJsonSeq.TElement
        {
            get { return typeof(KeyValuePair<,>).XMakeGenericType(TKey, TValue); }
        }

        void IJsonSeq.Add(Object element)
        {
            if (element.GetType().XGetGenericDefinition() == typeof(KeyValuePair<,>))
            {
                Add(element.Get("Key"), element.Get("Value"));
            }
            else if (element.GetType().XGetGenericDefinition() == typeof(Tuple<,>))
            {
                Add(element.Get("Item1"), element.Get("Item2"));
            }
            else
            {
                throw AssertionHelper.Fail();
            }
        }
    }
}